package cn.cyh.user.service.impl;

import cn.cyh.Dto.LoginDto;
import cn.cyh.basic.exception.BusinessException;
import cn.cyh.basic.uitls.AJaxResult;
import cn.cyh.basic.uitls.HttpClientUtils;
import cn.cyh.basic.uitls.MD5Utils;
import cn.cyh.basic.uitls.StrUtils;
import cn.cyh.user.contants.UserContants;
import cn.cyh.user.domain.LoginInfo;
import cn.cyh.user.domain.User;
import cn.cyh.user.domain.WxUser;
import cn.cyh.user.mapper.LoginInfoMapper;
import cn.cyh.user.mapper.UserMapper;
import cn.cyh.user.mapper.WxUserMapper;
import cn.cyh.user.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LoginInfoMapper loginInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public Map<String, Object> accountLogin(LoginDto loginDto) {
        //校验参数不能为空
        if (StringUtils.isEmpty(loginDto.getUsername())
                || StringUtils.isEmpty(loginDto.getType())
                || StringUtils.isEmpty(loginDto.getPassword())) {
            throw new BusinessException("用户密码错误");
        }
        // 查询数据（username+type）
        LoginInfo loginInfo = loginInfoMapper.loadByLoginDto(loginDto);
        // 查不到
        if (loginInfo == null) {
            throw new BusinessException("用户密码错误");
        }
        // 查到了校验密码
        // 盐值
        String salt = loginInfo.getSalt();
        String md5pwd = loginInfo.getPassword();
        String password = loginDto.getPassword();
        // 不成功
        // 加盐加密  （同userservice实现类中一致）
        if (!md5pwd.equals(MD5Utils.encrypByMd5(password + salt))) {
            throw new BusinessException("用户密码错误");
        }
        // 成功 保存redis 对象需要序列化
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("loginInfo", loginInfo);
        // 将敏感信息滞空
        loginInfo.setSalt(null);
        loginInfo.setPassword(null);
        return map;
    }

    @Override
    public AJaxResult wechat(Map<String, String> params) {
        String code = params.get("code");
        if (!StringUtils.hasLength(code)) {
            throw new BusinessException("没有授权码");
        }
        // 获取令牌
        String tokenUrl = UserContants.WXUSER_GET_TOKEN_URL
                .replace("APPID", UserContants.APPID)
                .replace("SECRET", UserContants.SECRET)
                .replace("CODE", code);
        // 通过code获取token
        String tokenStr = HttpClientUtils.httpGet(tokenUrl);
        JSONObject jsonObject = JSONObject.parseObject(tokenStr);
        // 拿值
        String openid = jsonObject.getString("openid");// 微信号
        String access_Token = jsonObject.getString("access_token");//令牌
        // 根据openid查询t_user
        WxUser wxUser = wxUserMapper.loadByOpenId(openid);

        // 判断是否绑定过 （是否扫码过）
        if (wxUser != null && wxUser.getUser_id() != null) {
            LoginInfo loginInfo = loginInfoMapper.loadByUserId(wxUser.getUser_id());
            // 免密登录
            // 成功 保存redis 对象需要序列化
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
            Map<String, Object> map = new HashMap<>();
            map.put("token", token);
            map.put("loginInfo", loginInfo);
            // 将敏感信息滞空
            loginInfo.setSalt(null);
            loginInfo.setPassword(null);
            return AJaxResult.myself().setResultObj(map);
        }
        // 没有扫码 第一次扫码 跳转到绑定页面 携带token和openid
        String binderUrlParams = "?accessToken=" + access_Token + "&openId=" + openid;
        return AJaxResult.myself().setSuccess(false).setResultObj(binderUrlParams);
    }

    @Override
    public Map<String, Object> binder(Map<String, String> params) {
        // 非空校验
        String phone = params.get("phone");
        String verifyCode = params.get("verifyCode");
        String accessToken = params.get("accessToken");
        String openId = params.get("openId");
        if (!StringUtils.hasLength(phone)
                || !StringUtils.hasLength(verifyCode)
                || !StringUtils.hasLength(accessToken)
                || !StringUtils.hasLength(openId)) {
            throw new BusinessException("信息为空");
        }
        // 验证码校验
        Object codeTmp = redisTemplate.opsForValue().get(UserContants.BUSINESS_BINDER_PREFIX + phone);
        if (codeTmp == null) {
            throw new BusinessException("验证码已经过期 请重新获取 ");
        }
        // 比对验证码
        // 不区分大小写
        String code = codeTmp.toString().split(":")[0];
        if (!verifyCode.equalsIgnoreCase(code)) {
            throw new BusinessException("验证码错误");
        }

        User userTmp = userMapper.loadByPhone(phone);
        User user = null;
        LoginInfo loginInfo = null;

        if (userTmp != null) { // 已经注册 可以绑定微信
            user = userTmp;
            loginInfo = loginInfoMapper.loadById(user.getLogininfo_id());

        } else {// 没有用户需要创建平台用户
            user = initUser(phone);
            loginInfo = user2LoginInfo(user);
            loginInfoMapper.save(loginInfo);
            user.setLogininfo_id(loginInfo.getId());
            userMapper.save(user);
        }
        // 通过token+openid获取微信用户信息
        String Userurl = UserContants.WXUSER_GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String wxUserTmp = HttpClientUtils.httpGet(Userurl);
        WxUser wxUser = initWxUser(wxUserTmp, user);
        wxUserMapper.save(wxUser);
        // 免密登录
        // 判断是否绑定过 （是否扫码过）
        if (wxUser != null && wxUser.getUser_id() != null) {
            loginInfo = loginInfoMapper.loadByUserId(wxUser.getUser_id());
            // 免密登录
            // 成功 保存redis 对象需要序列化
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
            Map<String, Object> map = new HashMap<>();
            map.put("token", token);
            map.put("loginInfo", loginInfo);
            // 将敏感信息滞空
            loginInfo.setSalt(null);
            loginInfo.setPassword(null);
            return map;
        }
        return null;
    }

    private WxUser initWxUser(String wxUserTmp, User user) {
        // 装填微信用户信息
        JSONObject jsonObject = JSONObject.parseObject(wxUserTmp);
        WxUser wxUser =  new WxUser();
        wxUser.setUser_id(user.getId());//绑定用户
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }

    private LoginInfo user2LoginInfo(User user) {
        LoginInfo loginInfo = new LoginInfo();
        BeanUtils.copyProperties(user,loginInfo);
        loginInfo.setType(1);
        return loginInfo;
    }

    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        // 盐值
        String salt = StrUtils.getComplexRandomString(32);
        // 加密加盐 生成随机密码
        String byMd5 = MD5Utils.encrypByMd5("9" + salt);
        user.setSalt(salt);
        user.setPassword(byMd5);
        return user;
    }
}
